package com.ludomancy.starwave;

import java.awt.Point;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;

public class Game implements ShipTypes
{
	public static boolean EDITOR = false;
	public static Game game;
	public Player me;
	public AIPlayer ai;
	public Vector ships = new Vector();
	public static final int GRID_WIDTH = 9;
	public static final int GRID_HEIGHT = 5;
	public static final int ACTIVE_AREA_LENGTH = 4;
	
	public static final int PHASE_SETUP = 1;
	public static final int PHASE_MOVING = 2;
	public static final int PHASE_ATTACKING = 3;
	public static final int PHASE_SOLVE_OUTCOME = 4;
	public static final int PHASE_MOTHERSHIP_DEATH = 6;
	public static final int PHASE_LEVEL_LOST = 7;
	public static final int PHASE_LEVEL_WON = 8;
	public static final int PHASE_COLLISIONS = 9;
	
	public int phase = PHASE_SETUP;
	public Level currentMission;
	
	private boolean collided = false;
	private Vector collisionAnimations;
	private Vector collidedShips;
	
	Game(int level)
	{
		game = this;
		ai = new AIPlayer(-1);
		me = new Player(1);
		currentMission = Level.setupMission(me, ai, level);
	}
	
	void addAnimation(Animation anim)
	{
		StarWaveApplet.mainWidget.grid.pendingAnimations.add(anim);
	}
	
	public Ship[] getShips(int px, int py)
	{
		Vector shipsVector = new Vector();
		for (int i = 0; i < ships.size(); i++)
		{
			Ship ship = (Ship) ships.elementAt(i);
			if(ship.px == px && ship.py == py)
			{
				shipsVector.add(ship);
			}
		}
		Ship[] ret = new Ship[shipsVector.size()];
		shipsVector.copyInto(ret);
		return ret;
	}
	
	private void setPhase(int newPhase)
	{
		phase = newPhase;
		switch(newPhase)
		{
			case PHASE_SETUP:
				StarWaveApplet.mainWidget.endTurnButton.setVisible(true);
				StarWaveApplet.mainWidget.retryButton.setVisible(false);
				StarWaveApplet.mainWidget.nextLevelButton.setVisible(false);
				StarWaveApplet.mainWidget.grid.clearCorpses();
				StarWaveApplet.mainWidget.grid.setEnabled(true);
				break;
				
			case PHASE_MOVING:
				StarWaveApplet.mainWidget.endTurnButton.setVisible(false);
				StarWaveApplet.mainWidget.grid.setEnabled(false);
				
				Collections.sort(ships, new ShipOwnerComparator());
				
				// prepare collisions
				collided = false;
				collisionAnimations = new Vector();
				collidedShips = new Vector();
				
				for (int i = 0; i < ships.size(); i++)
				{
					Ship ship = (Ship) ships.elementAt(i);
					ship.move();
				}
				break;
				
			case PHASE_COLLISIONS:
				StarWaveApplet.mainWidget.grid.pendingAnimations.clear();
				if(!collided)
				{
					endPhase();
				}
				else
				{
					// add the idle animations for those ships that didn't collide
					for (Iterator iter = ships.iterator(); iter.hasNext();)
					{
						Ship ship = (Ship) iter.next();
						if(!collidedShips.contains(ship))
						{
							StarWaveApplet.mainWidget.grid.pendingAnimations.add(new IdleAnimation(ship));
						}
					}
					// add the collision anims
					StarWaveApplet.mainWidget.grid.pendingAnimations.addAll(collisionAnimations);
				}
				break;
				
			case PHASE_ATTACKING:
				StarWaveApplet.mainWidget.grid.pendingAnimations.clear();
				boolean turnHasAttacks = false;
				for (int i = 0; i < ships.size(); i++)
				{
					Ship ship = (Ship) ships.elementAt(i);
					if(!ship.isDead())
					{
						if(!ship.attack().isEmpty())
						{
							turnHasAttacks = true;
						}
					}
				}
				
				if(!turnHasAttacks)
				{
					StarWaveApplet.mainWidget.grid.pendingAnimations.clear();
					endPhase();
				}
				else
				{
					Collections.sort(StarWaveApplet.mainWidget.grid.pendingAnimations, new AttackComparator(StarWaveApplet.mainWidget.grid.pendingAnimations));
				}
				break;
								
			case PHASE_MOTHERSHIP_DEATH:
				StarWaveApplet.mainWidget.myMothership.startDeathAnimation();
				break;
				
			case PHASE_LEVEL_LOST:
//				for (Iterator iter = StarWaveApplet.mainWidget.grid.shipCorpses.iterator(); iter.hasNext();)
//				{
//					Ship ship = (Ship) iter.next();
//					ship.restoreInitialPosition();
//				}
//				for (Iterator iter = ships.iterator(); iter.hasNext();)
//				{
//					Ship ship = (Ship) iter.next();
//					ship.restoreInitialPosition();
//				}
				StarWaveApplet.mainWidget.endTurnButton.setVisible(false);
				StarWaveApplet.mainWidget.retryButton.setVisible(true);
				break;

			case PHASE_LEVEL_WON:
				StarWaveApplet.mainWidget.endTurnButton.setVisible(false);
				StarWaveApplet.mainWidget.nextLevelButton.setVisible(true);
				break;

			default:
		}
	}
	
	public void endPhase()
	{
		switch(phase)
		{
			case PHASE_SETUP:
				setPhase(PHASE_MOVING);
//				new Sound("launch.wav").play();
				break;
				
			case PHASE_MOVING:
				setPhase(PHASE_COLLISIONS);
				break;
				
			case PHASE_COLLISIONS:
				setPhase(PHASE_ATTACKING);
				break;
				
			case PHASE_ATTACKING:
				resolveDeaths();
				if(getAliveShips(ai) == 0)
				{
					if(EDITOR)
					{
						setPhase(PHASE_MOTHERSHIP_DEATH);
					}
					else
					{
						setPhase(PHASE_LEVEL_WON);
					}
				}
				else
				if(aiReachedMothership())
				{
					setPhase(PHASE_MOTHERSHIP_DEATH);
				}
				else
				{
					setPhase(PHASE_MOVING);
				}
				break;
				
			case PHASE_MOTHERSHIP_DEATH:
				setPhase(PHASE_LEVEL_LOST);
				break;
				
			case PHASE_LEVEL_LOST:
				StarWaveApplet.mainWidget.levelEnd(false);
				break;
				
			case PHASE_LEVEL_WON:
				StarWaveApplet.mainWidget.levelEnd(true);
				break;
		}
	}
	
	private boolean aiReachedMothership()
	{
		for (int i = 0; i < ships.size(); i++)
		{
			Ship ship = (Ship) ships.elementAt(i);
			if(ship.owner == ai && ship.px == 0)
			{
				return true;
			}
		}		
		return false;
	}

	private int getAliveShips(Player player)
	{
		int c = 0;
		for (int i = 0; i < ships.size(); i++)
		{
			Ship ship = (Ship) ships.elementAt(i);
			if(ship.owner == player)
			{
				c++;
			}
		}
		return c;
	}
				
	private boolean resolveDeaths()
	{
		boolean hasDeaths = false;
		for (int i = 0; i < ships.size();)
		{
			Ship ship = (Ship) ships.elementAt(i);
			if(ship.isDead())
			{
				hasDeaths = hasDeaths || ship.isDead();
				ships.removeElementAt(i);
				StarWaveApplet.mainWidget.grid.addCorpse(ship);
			}
			else
			{
				i++;
			}
		}
		return hasDeaths;
	}

	public boolean isInDeploymentField(Point pos)
	{
		return pos.x >= 0 && pos.x < ACTIVE_AREA_LENGTH;
	}
	
	public boolean positionAvailable(int x, int y)
	{
		return getShips(x, y).length == 0;
	}
	
	public boolean isTileSolid(int x, int y, Ship respectTo)
	{
		Ship[] s = getShips(x,y);
		for (int i = 0; i < s.length; i++)
		{
			if(s[i].isSolid() && (respectTo == null || respectTo.owner != s[i].owner))
			{
				return true;
			}
		}
		return false;
	}

	public boolean addShip(Ship ship)
	{
		if(positionAvailable(ship.px, ship.py))
		{
			ships.add(ship);
			return true;
		}
		return false;
	}	

	public void moveShip(Ship ship, int toX, int toY)
	{
		// check for collisions
		Ship[] previous = getShips(toX, toY);
		
		ship.px = toX;
		ship.py = toY;
		if(previous.length > 0)
		{
			for (int i = 0; i < previous.length; i++)
			{
				if(previous[i] != ship)
				{
					boolean processedCollision1 = ship.collide(previous[i], collisionAnimations);
					boolean processedCollision2 = previous[i].collide(ship, collisionAnimations); 
					collided = processedCollision1 || processedCollision2 || collided;
					if(processedCollision1)
					{
						collidedShips.add(ship);
					}
					if(processedCollision2)
					{
						collidedShips.add(previous[i]);
					}
				}
			}
		}
	}

	public boolean isWithinPlayfield(int px, int py)
	{
		return px >= 0 && px < Game.GRID_WIDTH && py >= 0 && py < Game.GRID_HEIGHT;
	}
	
}
